The purpose of this notebook is to create a neighborhood index that combines crime and cleanliness data. The index relies on 311 service request data and Part 1 violent crime data, both availble on Open Baltimore.
Brief Description of The Index
The index primarily relies on counts of violent crime and service requests per 1,000 residents. This is done to remove the influence of population on the counts of these events. The per-capita metrics are then scaled to between 0 and 1 to build up the overall index.
All Part 1 crime types are used.
The SR types used are:
Illegal Dumping:
- HCD-Illegal Dumping
- SW-SIU Clean Up
Property Maintenance:
- HCD-Sanitation Property
- SW-Boarding
- SW-HGW
- SW-Cleaning
Right-of-Way Cleaning
- SW-Dirty Street
- SW-Dirty Alley
knitr::opts_chunk$set(echo = T,
warning = F,
message = F,
include = T,
fig.width = 4,
fig.height = 3)
library(tidyverse)
library(ggiteam)
library(lubridate)
library(readxl)
library(spdplyr)
library(leaflet)
library(RSocrata)
library(geojsonsf)
library(ggmap)
library(rgdal)
library(scales)
library(sf)
library(htmltools)
register_google("AIzaSyByyKUj4QaAlzNtPJPw-HkEEr7d4hTawO0")
sr_query <- paste0("https://data.baltimorecity.gov/resource/9agw-sxsr.json",
"?$where=",
"((srtype like 'SW-Boarding' OR ",
"srtype like 'SW-Cleaning' OR ",
"srtype like 'SW-HGW' OR ",
"srtype like 'SW-Dirty Alley' OR ",
"srtype like 'SW-Dirty Street' OR ",
"srtype like 'HCD-Illegal Dumping' OR ",
"srtype like 'HCD-SIU' OR ",
"srtype like 'SW-SIU Clean Up' OR ",
"srtype like 'HCD-Sanitation Property') AND ",
"date_extract_y(createddate)==2019)")
sr <- read.socrata(url = sr_query)
sr <- sr %>%
mutate(
latitude = as.numeric(latitude),
longitude = as.numeric(longitude),
neighborhood = toupper(neighborhood))
crime_query <- paste0("https://data.baltimorecity.gov/resource/wsfq-mvij.json?$where=",
"(Description like 'HOMICIDE' OR ",
"Description like 'SHOOTING' OR ",
"Description like 'AGG. ASSAULT' OR ",
"Description like 'RAPE' OR ",
"contains(Description, 'ROBBERY')) AND ",
"date_extract_y(crimedate)==2019")
crime <- read.socrata(crime_query)
cityline_url <- "https://data.baltimorecity.gov/resource/nfyc-pejx.geojson"
# surely there is a better way, and i tried, but couldn't get anything else to work.
# from geojson to sf to spatial df. geojson_sp didn't work for me.
cityline <- geojson_sf(cityline_url)
cityline <- as_Spatial(cityline)
cityline <- spTransform(cityline, CRS("+init=epsg:4326"))
hoods.url <- "https://data.baltimorecity.gov/resource/h3fx-54q3.geojson"
# surely there is a better way, and i tried, but couldn't get anything else to work.
# from geojson to sf to spatial df. geojson_sp didn't work for me.
hoods <- geojson_sf(hoods.url)
hoods <- as_Spatial(hoods)
hoods <- spTransform(hoods, CRS("+init=epsg:4326"))
# join acs data to hoods
hoods_pop <- read_excel("../data/raw/Neighborhood Pop.xlsx")
hoods@data <- left_join(hoods@data, hoods_pop, by = c("label" = "Name"))
# bpd facilities to remove
facilities <- c(
"300 E MADISON ST", # central booking
"1400 E NORTH AVE", # district court
"1900 ARGONNE DR", # northeastern
"2200 W Cold Spring Ln", # northern
"1000 N MOUNT ST", # western
"5200 REISTERSTOWN RD ", # northwest
"1600 EDISON HWY", # eastern
"400 FONTHILL AVE", # southwest
"0 CHERRY HILL RD", # southern
"600 E FAYETTE ST", # central/hq
"5700 EASTERN AVE", # southeast
"2000 W BALTIMORE ST", # bon secours
"4000 DEEPWOOD RD", # loch raven va
"300 N GAY ST", # juv booking
"4900 EASTERN AV", # bayview
"1800 ORLEANS ST", # jhh downtown
"600 N WOLFE ST", # jhh downtown
"0 S GREENE ST", # umd medical center
"3400 N CALVERT ST" # union memorial
)
Population distribution of Baltimore neighborhoods.
hoods@data %>%
ggplot(aes(ACS_2013_2017)) +
geom_histogram() +
theme_iteam_google_docs()

Tenth percentile for population:
quantile(hoods$ACS_2013_2017, 0.1, na.rm = T)
10%
174.7548
Analysis
crime_labeled <- crime %>%
filter(
!is.na(latitude),
!(location %in% facilities)
) %>%
st_as_sf(coords = c("longitude", "latitude"), crs = 4326) %>%
st_join(st_as_sf(hoods), join = st_within, left = F)
crime_hood_counts <- crime_labeled %>%
data.frame() %>%
count(description, label) %>%
spread(key = description, value = n) %>%
replace(is.na(.), 0) %>%
transmute(
label = label,
agg_assault = `AGG. ASSAULT`,
rape = RAPE,
homicide_shootings = HOMICIDE + SHOOTING,
robbery = `ROBBERY - COMMERCIAL` +
`ROBBERY - CARJACKING` +
`ROBBERY - RESIDENCE` +
`ROBBERY - STREET`)
sr_labeled <- sr %>%
filter(
!is.na(latitude)
) %>%
st_as_sf(coords = c("longitude", "latitude"), crs = 4326) %>%
st_join(st_as_sf(hoods), join = st_within, left = F)
sr_hood_counts <- sr_labeled %>%
data.frame() %>%
count(srtype, label) %>%
spread(key = srtype, value = n) %>%
replace(is.na(.), 0) %>%
transmute(
label = label,
illegal_dumping = `HCD-Illegal Dumping` + `SW-SIU Clean Up`,
property_maintenance = `HCD-Sanitation Property` +
`SW-Boarding` +
`SW-Cleaning` +
`SW-HGW`,
right_of_way = `SW-Dirty Street` + `SW-Dirty Alley`
)
# to per 1,000 residents
to_per_capita <- function(x){1000 * x / hoods$ACS_2013_2017}
hood_metrics <- hoods
hood_metrics@data <- hood_metrics@data %>%
select(-acres,
-nbrdesc,
-shape_leng,
-shape_area,
-color_2,
-Decennial2010)
hood_metrics@data <- hood_metrics@data %>%
left_join(
crime_hood_counts,
by = "label") %>%
left_join(
sr_hood_counts,
by = "label"
) %>%
mutate_at(
vars(
illegal_dumping,
property_maintenance,
right_of_way,
homicide_shootings,
robbery,
agg_assault,
rape),
list(per_1000_res = to_per_capita))
Distribution of per capita rates of crime and service requests:
hood_metrics@data %>%
select(
label,
illegal_dumping_per_1000_res,
property_maintenance_per_1000_res,
right_of_way_per_1000_res,
homicide_shootings_per_1000_res,
robbery_per_1000_res,
agg_assault_per_1000_res,
rape_per_1000_res
) %>%
pivot_longer(-label) %>%
ggplot(aes(value)) +
facet_wrap(~name, scales = "free") +
geom_histogram(bins = 50) +
theme_iteam_google_docs() +
labs(title = "2019 Events per 1,000 Residents")

In all cases, outlier neighborhoods with very small populations skew data.
Try removing neighborhoods with less than 150 residents (10% of neighborhoods). These are typically parks, industrial areas, etc.
hood_metrics@data %>%
filter(ACS_2013_2017 >= 150) %>%
select(
label,
illegal_dumping_per_1000_res,
property_maintenance_per_1000_res,
right_of_way_per_1000_res,
homicide_shootings_per_1000_res,
robbery_per_1000_res,
agg_assault_per_1000_res,
rape_per_1000_res
) %>%
pivot_longer(-label) %>%
ggplot(aes(value)) +
facet_wrap(~name, scales = "free") +
geom_histogram(bins = 50) +
theme_iteam_google_docs() +
labs(title = "2019 Events per 1,000 Residents\nNeighborhoods with >= 150 Residents")

Going forward, removing neighborhoods with less than 150 residents.
hood_metrics_over150 <- subset(hood_metrics, hood_metrics$ACS_2013_2017 > 150)
hood_metrics_over150 <- subset(hood_metrics_over150, !grepl("INDUSTRIAL", label, ignore.case = T))
Number of neighborhoods with at least one homicide or shooting:
hood_metrics_over150@data %>%
count(homicide_shootings >= 1)
Will likely assign 1 to neighborhoods with at least 1 homicide or shooting, 0 to all others. This will ensure neighborhoods with gun violence are given precedence.
Building The Index
All parameters will be scaled to between 0 and 1 because variables are on different scales.
# scale per capita
scale_index <- function(x){rescale(x, to = c(0,1))}
hood_metrics_over150@data <- hood_metrics_over150@data %>%
mutate(
homicide_shootings_index = ifelse(homicide_shootings > 0, 1, 0),
rape_index = ifelse(rape > 0, 1, 0)) %>%
mutate_at(
vars(
illegal_dumping_per_1000_res,
property_maintenance_per_1000_res,
right_of_way_per_1000_res,
homicide_shootings_per_1000_res,
robbery_per_1000_res,
agg_assault_per_1000_res,
rape_per_1000_res),
list(index = scale_index)
)
# plot rescaled data
hood_metrics_over150@data %>%
select(
label,
illegal_dumping_per_1000_res_index,
property_maintenance_per_1000_res_index,
right_of_way_per_1000_res_index,
homicide_shootings_per_1000_res_index,
robbery_per_1000_res_index,
agg_assault_per_1000_res_index,
rape_per_1000_res_index
) %>%
pivot_longer(-label) %>%
ggplot(aes(value)) +
facet_wrap(~name, scales = "free") +
geom_histogram(bins = 50) +
theme_iteam_google_docs() +
labs(title = "Standardized (between 0 and 1) 2019 Events per 1,000 Residents\nNeighborhoods with >= 150 Residents")

Again, all metrics have been scaled to between 0 and 1. Combine crime metrics into a homicide and shooting parameter (0 if none in neighborhood, 1 if at least 1) and an “other violent crime” parameter where:
\[ HomicideShootingsIndex = \begin{cases}
1 & \text{if $N_{homicides}+N_{shootings} > 0$ } \\
0 & \text{otherwise} \end{cases}\]
\[ OtherViolentCrimeIndex = \frac{1}{3}(RapeIndex+ AggAssaultIndex + RobberyIndex) \]
Combining the two crime indices:
\[ CrimeIndex = \frac{1}{2} (HomicideShootingsIndex + OtherViolentCrimeIndex) \]
# create combined index
hood_metrics_over150@data <- hood_metrics_over150@data %>%
rowwise() %>%
mutate(
other_violent_crime_index =
mean(
c(rape_per_1000_res_index,
agg_assault_per_1000_res_index,
robbery_per_1000_res_index),
na.rm = T),
grime_index = mean(
c(illegal_dumping_per_1000_res_index,
property_maintenance_per_1000_res_index,
right_of_way_per_1000_res_index),
na.rm = T)
) %>%
ungroup() %>%
mutate(crime_index = 0.5 * homicide_shootings_per_1000_res_index +
0.5 * other_violent_crime_index,
crime_grime_index = (2/3) * crime_index + (1/3) * grime_index,
crime_grime_index_quadrature = sqrt(crime_index^2 + grime_index^2))
Now creating the “grime” index:
\[ GrimeIndex = \frac{1}{3}(IllegalDumpingIndex + PropMaintenanceIndex + RightOfWayIndex) \] Combine into a single index. Crime weighted more heavily.
\[ CrimeGrimeIndex = \frac{2}{3}CrimeIndex + \frac{1}{3}GrimeIndex \]
Just Show Me The Results
# base_map <- get_map(
# location=c(lon = -76.61, lat = 39.3),
# zoom=12,
# maptype = 'toner-lite',
# source = 'stamen'
# )
#
# ggmap(base_map) +
# # geom_point(
# # data = repeat_offender_locations %>%
# # filter(!is.na(lon),
# # n >= 3),
# # aes(x = lon, y = lat),
# # color = "blue",
# # size = 2
# # )
# geom_polygon(
# data = fortify(hood_metrics_over150) %>%
# filter(!is.na(crime_grime_index)),
# aes(x = long, y = lat, group = group, fill = crime_grime_index),
# alpha = 0.9,color = "black"
# )# +
# # scale_fill_viridis_c(na.value = NA,
# # #values = rescale(c(0, 20, 70), c(0,1)),
# # option = "plasma",
# # guide_colorbar(title = "Annual DV Incidents\nper 1,000 Residents"))
# #
hoods@data <- hoods@data %>%
left_join(
hood_metrics_over150@data %>% select(-ACS_2013_2017),
by = "label"
)
# color palette for map
pal <- colorNumeric("viridis",
domain = hoods$crime_grime_index,
na.color = "transparent")
# labels
hoods@data <- hoods@data %>%
mutate(map_label = paste0(
"<b>",hoods$label, "</b><br>",
"Population: ", round(hoods$ACS_2013_2017, 0), "<br>",
"Crime & Grime Index: ", round(hoods$crime_grime_index, 2), "<br>",
"Crime Index: ", round(hoods$crime_index, 2), "<br>",
"Grime Index: ", round(hoods$grime_index, 2), "<br>",
"<br><b>2019 Crime</b><br>",
"Homicides + Shootings: ", hoods$homicide_shootings, "<br>",
"Rape: ", hoods$rape, "<br>",
"Aggravated Assault: ", hoods$agg_assault, "<br>",
"Robbery: ", hoods$robbery, "<br>",
"<br><b>2019 Service Requests</b><br>",
"Illegal Dumping SRs: ", hoods$illegal_dumping, "<br>",
"Property Maintenance SRs: ", hoods$property_maintenance, "<br>",
"Right-of-Way SRs: ", hoods$right_of_way, "<br>"
))
leaflet() %>%
setView(lng = -76.6, lat = 39.3, zoom = 11) %>%
addProviderTiles(providers$Stamen.TonerLite) %>%
addPolygons(data = hoods,
weight = 2,
fillColor = ~pal(hoods$crime_grime_index),
color = "black",
opacity = 0.9,
fillOpacity = 0.75,
label = hoods$label,
popup = ~lapply(hoods$map_label, HTML),
labelOptions = labelOptions(noHide = F,
#textOnly = T,
direction = 'right',
textsize = 2,
opacity = 1)) %>%
addControl("Baltimore<br>Crime & Grime Index<br><br>Click Neighborhood<br>For More Info",
position = "topleft") %>%
addLegend(pal = pal, values = hoods$crime_grime_index, position = "bottomright",
title = "Crime Grime Index")
Distribution of Indexes
Because of the homicide and shooting index being 1 for neighborhoods with at least one homicide or shooting and 0 for all others, the distribution is bifurcated into neighborhoods with and without shootings.
hoods@data %>%
ggplot(aes(crime_grime_index)) +
geom_histogram() +
theme_iteam_google_docs()

The List, In Order of Descending Crime-Grime Index
Some neighborhoods with very small populations still sneak onto the list because we only used 150 as the cut-off, but those can be manually dropped if not interested.
hoods@data %>%
arrange(desc(robbery_per_1000_res)) %>%
select(-acres, -nbrdesc, -shape_leng, -shape_area, -color_2, -Decennial2010) %>%
rename(neighborhood = label,
population_acs_2013_2017 = ACS_2013_2017)
#write_csv(the_list, "../data/processed/crime_grime_index_v3.csv")
top_20 <- hoods %>%
arrange(desc(crime_grime_index)) %>%
top_n(n = 20, wt = crime_grime_index)
color_list <- hoods@data %>%
arrange(desc(crime_grime_index)) %>%
mutate(top20_color = ifelse(row_number() <= 20, iteam.colors[1], NA)) %>%
select(label, top20_color)
hoods@data <- hoods@data %>%
left_join(color_list, by = "label")
Top 20 Neighborhoods
fill_pal <- colorFactor(hoods$top20_color, hoods$top20_color, na.color = "transparent")
leaflet() %>%
setView(lng = -76.6, lat = 39.3, zoom = 11) %>%
addProviderTiles(providers$Stamen.TonerLite) %>%
addPolygons(data = hoods,
weight = 2,
fillColor = ~fill_pal(hoods$top20_color),
color = "black",
opacity = 0.9,
fillOpacity = 0.75,
label = hoods$label,
popup = ~lapply(hoods$map_label, HTML),
labelOptions = labelOptions(noHide = F,
#textOnly = T,
direction = 'right',
textsize = 2,
opacity = 1)) %>%
addControl("Baltimore<br>Crime & Grime Index<br>Top 20 Neighborhoods<br><br>Click Neighborhood<br>For More Info",
position = "topleft")
Crime v. Grime
Red means the crime index was higher, blue means the grime index was higher.
hoods@data <- hoods@data %>% mutate(crime_grime_index_diff = crime_index - grime_index)
diff_pal <- colorNumeric("RdBu",
domain = hoods$crime_grime_index_diff,
na.color = "transparent", reverse = T)
leaflet() %>%
setView(lng = -76.6, lat = 39.3, zoom = 11) %>%
addProviderTiles(providers$Stamen.TonerLite) %>%
addPolygons(data = hoods,
weight = 2,
fillColor = ~diff_pal(hoods$crime_grime_index_diff),
color = "black",
opacity = 0.9,
fillOpacity = 0.75,
label = hoods$label,
popup = ~lapply(hoods$map_label, HTML),
labelOptions = labelOptions(noHide = F,
#textOnly = T,
direction = 'right',
textsize = 2,
opacity = 1)) %>%
addControl("Baltimore<br>Crime & Grime Index<br>Crime-Grime Difference<br><br>Click Neighborhood<br>For More Info",
position = "topleft") %>%
addLegend(pal = diff_pal, values = hoods$crime_grime_index_diff, position = "bottomright", title = "Red: More Crime<br>Blue: More Grime")
hoods@data %>%
filter(label %in% c("Milton-Montford",
"Carrollton Ridge",
"Penn North",
"Broadway East",
"Downtown")) %>%
arrange(desc(robbery_per_1000_res)) %>%
select(-acres, -nbrdesc, -shape_leng, -shape_area, -color_2, -Decennial2010) %>%
rename(neighborhood = label,
population_acs_2013_2017 = ACS_2013_2017)
hoods@data %>%
filter(label %in% c("Milton-Montford",
"Carrollton Ridge",
"Penn North",
"Broadway East",
"Downtown")) %>%
select(
label,
illegal_dumping_per_1000_res,
property_maintenance_per_1000_res,
right_of_way_per_1000_res,
homicide_shootings_per_1000_res,
robbery_per_1000_res,
agg_assault_per_1000_res,
rape_per_1000_res) %>%
pivot_longer(-label) %>%
ggplot(aes(label, value)) +
facet_wrap(~name, scales = "free") +
geom_col() +
coord_flip() +
theme_iteam_google_docs()

hoods@data %>%
filter(label %in% c("Milton-Montford",
"Carrollton Ridge",
"Penn North",
"Broadway East")) %>%
transmute(
Neighborhood = label,
`Illegal Dumping SRs per 1,000 Residents` = illegal_dumping_per_1000_res,
`Prop. Maintenance SRs per 1,000 Residents` = property_maintenance_per_1000_res,
`Right of Way SRs per 1,000 Residents` = right_of_way_per_1000_res,
`Homicides per 1,000 Residents` = homicide_shootings_per_1000_res,
`Robbery per 1,000 Residents` = robbery_per_1000_res,
`Agg. Assault per 1,000 Residents` = agg_assault_per_1000_res,
`Rape per 1,000 Residents` = rape_per_1000_res) %>%
pivot_longer(-Neighborhood) %>%
ggplot(aes(Neighborhood, value)) +
facet_wrap(facets = ~name, ncol = 2, scales = "free") +
geom_col() +
coord_flip() +
theme_iteam_google_docs() +
theme(axis.title.x = element_blank(),
axis.title.y = element_blank())

hoods@data %>%
filter(label %in% c("Milton-Montford",
"Carrollton Ridge",
"Penn North",
"Broadway East")) %>%
transmute(
Neighborhood = label,
`Illegal Dumping SRs` = illegal_dumping,
`Prop. Maintenance SRs` = property_maintenance,
`Right of Way SRs` = right_of_way,
`Homicides` = homicide_shootings,
`Robbery` = robbery,
`Agg. Assault ` = agg_assault,
`Rape` = rape) %>%
pivot_longer(-Neighborhood) %>%
ggplot(aes(Neighborhood, value)) +
facet_wrap(facets = ~name, ncol = 2, scales = "free") +
geom_col() +
coord_flip() +
theme_iteam_google_docs() +
theme(axis.title.x = element_blank(),
axis.title.y = element_blank())

LS0tCnRpdGxlOiAiQ3JpbWUgKyBHcmltZSBJbmRleCBEZXZlbG9wbWVudCIKYXV0aG9yOiAiSnVzdGluIEVsc3phc3oiCmVtYWlsOiAianVzdGluLmVsc3phc3pAYmFsdGltb3JlY2l0eS5nb3YiCmRhdGU6ICJUdWVzZGF5LCBKYW51YXJ5IDIxLCAyMDIwIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgZmlnX2hlaWdodDogNQogICAgZmlnX3dpZHRoOiAxMAogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogMQplZGl0b3Jfb3B0aW9uczogCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQotLS0KClRoZSBwdXJwb3NlIG9mIHRoaXMgbm90ZWJvb2sgaXMgdG8gY3JlYXRlIGEgbmVpZ2hib3Job29kIGluZGV4IHRoYXQgY29tYmluZXMgY3JpbWUgYW5kIGNsZWFubGluZXNzIGRhdGEuIFRoZSBpbmRleCByZWxpZXMgb24gWzMxMSBzZXJ2aWNlIHJlcXVlc3QgZGF0YV0oaHR0cHM6Ly9kYXRhLmJhbHRpbW9yZWNpdHkuZ292L0NpdHktU2VydmljZXMvMzExLUN1c3RvbWVyLVNlcnZpY2UtUmVxdWVzdHMvOWFndy1zeHNyKSBhbmQgW1BhcnQgMSB2aW9sZW50IGNyaW1lIGRhdGFdKGh0dHBzOi8vZGF0YS5iYWx0aW1vcmVjaXR5Lmdvdi9QdWJsaWMtU2FmZXR5L0JQRC1QYXJ0LTEtVmljdGltLUJhc2VkLUNyaW1lLURhdGEvd3NmcS1tdmlqKSwgYm90aCBhdmFpbGJsZSBvbiBPcGVuIEJhbHRpbW9yZS4KCiMgQnJpZWYgRGVzY3JpcHRpb24gb2YgVGhlIEluZGV4CgpUaGUgaW5kZXggcHJpbWFyaWx5IHJlbGllcyBvbiBjb3VudHMgb2YgdmlvbGVudCBjcmltZSBhbmQgc2VydmljZSByZXF1ZXN0cyAqcGVyIDEsMDAwIHJlc2lkZW50cyouIFRoaXMgaXMgZG9uZSB0byByZW1vdmUgdGhlIGluZmx1ZW5jZSBvZiBwb3B1bGF0aW9uIG9uIHRoZSBjb3VudHMgb2YgdGhlc2UgZXZlbnRzLiBUaGUgcGVyLWNhcGl0YSBtZXRyaWNzIGFyZSB0aGVuIHNjYWxlZCB0byBiZXR3ZWVuIDAgYW5kIDEgdG8gYnVpbGQgdXAgdGhlIG92ZXJhbGwgaW5kZXguCgpBbGwgUGFydCAxIGNyaW1lIHR5cGVzIGFyZSB1c2VkLgoKVGhlIFNSIHR5cGVzIHVzZWQgYXJlOgoKSWxsZWdhbCBEdW1waW5nOgoKLSBIQ0QtSWxsZWdhbCBEdW1waW5nCi0gU1ctU0lVIENsZWFuIFVwCgpQcm9wZXJ0eSBNYWludGVuYW5jZToKCi0gSENELVNhbml0YXRpb24gUHJvcGVydHkKLSBTVy1Cb2FyZGluZwotIFNXLUhHVwotIFNXLUNsZWFuaW5nCgpSaWdodC1vZi1XYXkgQ2xlYW5pbmcKCi0gU1ctRGlydHkgU3RyZWV0Ci0gU1ctRGlydHkgQWxsZXkKCgpgYGB7ciBzZXR1cCwgaW5jbHVkZSA9IFQsIGVjaG8gPSBULCBtZXNzYWdlID0gRkFMU0UsIGNhY2hlID0gVFJVRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBULCAKICAgICAgICAgICAgICAgICAgICAgIHdhcm5pbmcgPSBGLCAKICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGLAogICAgICAgICAgICAgICAgICAgICAgaW5jbHVkZSA9IFQsCiAgICAgICAgICAgICAgICAgICAgICBmaWcud2lkdGggPSA0LAogICAgICAgICAgICAgICAgICAgICAgZmlnLmhlaWdodCA9IDMpCmBgYAoKYGBge3IgbGlicmFyaWVzfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShnZ2l0ZWFtKQpsaWJyYXJ5KGx1YnJpZGF0ZSkKbGlicmFyeShyZWFkeGwpCmxpYnJhcnkoc3BkcGx5cikKbGlicmFyeShsZWFmbGV0KQpsaWJyYXJ5KFJTb2NyYXRhKQpsaWJyYXJ5KGdlb2pzb25zZikKbGlicmFyeShnZ21hcCkKbGlicmFyeShyZ2RhbCkKbGlicmFyeShzY2FsZXMpCmxpYnJhcnkoc2YpCmxpYnJhcnkoaHRtbHRvb2xzKQoKCnJlZ2lzdGVyX2dvb2dsZSgiQUl6YVN5Qnl5S1VqNFFhQWx6TnRQSlB3LUhrRUVyN2Q0aFRhd08wIikKYGBgCiAKYGBge3IgbG9hZF9zciwgY2FjaGUgPSBUfQpzcl9xdWVyeSA8LSBwYXN0ZTAoImh0dHBzOi8vZGF0YS5iYWx0aW1vcmVjaXR5Lmdvdi9yZXNvdXJjZS85YWd3LXN4c3IuanNvbiIsCiAgICAgICAgICAgICAgICAiPyR3aGVyZT0iLAogICAgICAgICAgICAgICAgIigoc3J0eXBlIGxpa2UgJ1NXLUJvYXJkaW5nJyBPUiAiLAogICAgICAgICAgICAgICAgInNydHlwZSBsaWtlICdTVy1DbGVhbmluZycgT1IgIiwKICAgICAgICAgICAgICAgICJzcnR5cGUgbGlrZSAnU1ctSEdXJyBPUiAiLAogICAgICAgICAgICAgICAgInNydHlwZSBsaWtlICdTVy1EaXJ0eSBBbGxleScgT1IgIiwKICAgICAgICAgICAgICAgICJzcnR5cGUgbGlrZSAnU1ctRGlydHkgU3RyZWV0JyBPUiAiLAogICAgICAgICAgICAgICAgInNydHlwZSBsaWtlICdIQ0QtSWxsZWdhbCBEdW1waW5nJyBPUiAiLAogICAgICAgICAgICAgICAgInNydHlwZSBsaWtlICdIQ0QtU0lVJyBPUiAiLAogICAgICAgICAgICAgICAgInNydHlwZSBsaWtlICdTVy1TSVUgQ2xlYW4gVXAnIE9SICIsCiAgICAgICAgICAgICAgICAic3J0eXBlIGxpa2UgJ0hDRC1TYW5pdGF0aW9uIFByb3BlcnR5JykgQU5EICIsCiAgICAgICAgICAgICAgICAiZGF0ZV9leHRyYWN0X3koY3JlYXRlZGRhdGUpPT0yMDE5KSIpCgpzciA8LSByZWFkLnNvY3JhdGEodXJsID0gc3JfcXVlcnkpCgpzciA8LSBzciAlPiUgCiAgbXV0YXRlKAogICAgbGF0aXR1ZGUgPSBhcy5udW1lcmljKGxhdGl0dWRlKSwgCiAgICBsb25naXR1ZGUgPSBhcy5udW1lcmljKGxvbmdpdHVkZSksCiAgICBuZWlnaGJvcmhvb2QgPSB0b3VwcGVyKG5laWdoYm9yaG9vZCkpCmBgYAoKYGBge3IgbG9hZF9jcmltZSwgY2FjaGUgPSBUfQpjcmltZV9xdWVyeSA8LSBwYXN0ZTAoImh0dHBzOi8vZGF0YS5iYWx0aW1vcmVjaXR5Lmdvdi9yZXNvdXJjZS93c2ZxLW12aWouanNvbj8kd2hlcmU9IiwKICAgICAgICAgICAgICAgICIoRGVzY3JpcHRpb24gbGlrZSAnSE9NSUNJREUnIE9SICIsCiAgICAgICAgICAgICAgICAiRGVzY3JpcHRpb24gbGlrZSAnU0hPT1RJTkcnIE9SICIsIAogICAgICAgICAgICAgICAgIkRlc2NyaXB0aW9uIGxpa2UgJ0FHRy4gQVNTQVVMVCcgT1IgIiwKICAgICAgICAgICAgICAgICJEZXNjcmlwdGlvbiBsaWtlICdSQVBFJyBPUiAiLAogICAgICAgICAgICAgICAgImNvbnRhaW5zKERlc2NyaXB0aW9uLCAnUk9CQkVSWScpKSBBTkQgIiwKICAgICAgICAgICAgICAgICJkYXRlX2V4dHJhY3RfeShjcmltZWRhdGUpPT0yMDE5IikKCmNyaW1lIDwtIHJlYWQuc29jcmF0YShjcmltZV9xdWVyeSkKYGBgCgpgYGB7ciBjaXR5bGluZX0KY2l0eWxpbmVfdXJsIDwtICJodHRwczovL2RhdGEuYmFsdGltb3JlY2l0eS5nb3YvcmVzb3VyY2UvbmZ5Yy1wZWp4Lmdlb2pzb24iCgojIHN1cmVseSB0aGVyZSBpcyBhIGJldHRlciB3YXksIGFuZCBpIHRyaWVkLCBidXQgY291bGRuJ3QgZ2V0IGFueXRoaW5nIGVsc2UgdG8gd29yay4KIyBmcm9tIGdlb2pzb24gdG8gc2YgdG8gc3BhdGlhbCBkZi4gZ2VvanNvbl9zcCBkaWRuJ3Qgd29yayBmb3IgbWUuCmNpdHlsaW5lIDwtIGdlb2pzb25fc2YoY2l0eWxpbmVfdXJsKQpjaXR5bGluZSA8LSBhc19TcGF0aWFsKGNpdHlsaW5lKQpjaXR5bGluZSA8LSBzcFRyYW5zZm9ybShjaXR5bGluZSwgQ1JTKCIraW5pdD1lcHNnOjQzMjYiKSkKCmBgYAoKCmBgYHtyIGxvYWRfbmVpZ2hib3Job29kc30KaG9vZHMudXJsIDwtICJodHRwczovL2RhdGEuYmFsdGltb3JlY2l0eS5nb3YvcmVzb3VyY2UvaDNmeC01NHEzLmdlb2pzb24iCgojIHN1cmVseSB0aGVyZSBpcyBhIGJldHRlciB3YXksIGFuZCBpIHRyaWVkLCBidXQgY291bGRuJ3QgZ2V0IGFueXRoaW5nIGVsc2UgdG8gd29yay4KIyBmcm9tIGdlb2pzb24gdG8gc2YgdG8gc3BhdGlhbCBkZi4gZ2VvanNvbl9zcCBkaWRuJ3Qgd29yayBmb3IgbWUuCmhvb2RzIDwtIGdlb2pzb25fc2YoaG9vZHMudXJsKQpob29kcyA8LSBhc19TcGF0aWFsKGhvb2RzKQpob29kcyA8LSBzcFRyYW5zZm9ybShob29kcywgQ1JTKCIraW5pdD1lcHNnOjQzMjYiKSkKYGBgCgpgYGB7cn0KIyBqb2luIGFjcyBkYXRhIHRvIGhvb2RzCmhvb2RzX3BvcCA8LSByZWFkX2V4Y2VsKCIuLi9kYXRhL3Jhdy9OZWlnaGJvcmhvb2QgUG9wLnhsc3giKQpob29kc0BkYXRhIDwtIGxlZnRfam9pbihob29kc0BkYXRhLCBob29kc19wb3AsIGJ5ID0gYygibGFiZWwiID0gIk5hbWUiKSkKYGBgCgoKYGBge3J9CiMgYnBkIGZhY2lsaXRpZXMgdG8gcmVtb3ZlCmZhY2lsaXRpZXMgPC0gYygKICAiMzAwIEUgTUFESVNPTiBTVCIsICMgY2VudHJhbCBib29raW5nCiAgIjE0MDAgRSBOT1JUSCBBVkUiLCAjIGRpc3RyaWN0IGNvdXJ0CiAgIjE5MDAgQVJHT05ORSBEUiIsICMgbm9ydGhlYXN0ZXJuCiAgIjIyMDAgVyBDb2xkIFNwcmluZyBMbiIsICMgbm9ydGhlcm4KICAiMTAwMCBOIE1PVU5UIFNUIiwgIyB3ZXN0ZXJuCiAgIjUyMDAgUkVJU1RFUlNUT1dOIFJECSIsICMgbm9ydGh3ZXN0CiAgIjE2MDAgRURJU09OIEhXWSIsICMgZWFzdGVybgogICI0MDAgRk9OVEhJTEwgQVZFIiwgIyBzb3V0aHdlc3QKICAiMCBDSEVSUlkgSElMTCBSRCIsICMgc291dGhlcm4KICAiNjAwIEUgRkFZRVRURSBTVCIsICMgY2VudHJhbC9ocQogICI1NzAwIEVBU1RFUk4gQVZFIiwgIyBzb3V0aGVhc3QKICAiMjAwMCBXIEJBTFRJTU9SRSBTVCIsICAjIGJvbiBzZWNvdXJzCiAgIjQwMDAgREVFUFdPT0QgUkQiLCAjIGxvY2ggcmF2ZW4gdmEKICAiMzAwIE4gR0FZIFNUIiwgIyBqdXYgYm9va2luZwogICI0OTAwIEVBU1RFUk4gQVYiLCAjIGJheXZpZXcKICAiMTgwMCBPUkxFQU5TIFNUIiwgIyBqaGggZG93bnRvd24KICAiNjAwIE4gV09MRkUgU1QiLCAjIGpoaCBkb3dudG93bgogICIwIFMgR1JFRU5FIFNUIiwgIyB1bWQgbWVkaWNhbCBjZW50ZXIKICAiMzQwMCBOIENBTFZFUlQgU1QiICMgdW5pb24gbWVtb3JpYWwKKQoKYGBgCgpQb3B1bGF0aW9uIGRpc3RyaWJ1dGlvbiBvZiBCYWx0aW1vcmUgbmVpZ2hib3Job29kcy4KCmBgYHtyIGZpZy5oZWlnaHQgPSAxLCBmaWcud2lkdGggPSAyfQpob29kc0BkYXRhICU+JQogIGdncGxvdChhZXMoQUNTXzIwMTNfMjAxNykpICsKICBnZW9tX2hpc3RvZ3JhbSgpICsKICB0aGVtZV9pdGVhbV9nb29nbGVfZG9jcygpCmBgYAoKVGVudGggcGVyY2VudGlsZSBmb3IgcG9wdWxhdGlvbjoKCmBgYHtyfQpxdWFudGlsZShob29kcyRBQ1NfMjAxM18yMDE3LCAwLjEsIG5hLnJtID0gVCkKYGBgCgojIEFuYWx5c2lzCgpgYGB7cn0KY3JpbWVfbGFiZWxlZCA8LSBjcmltZSAlPiUKICBmaWx0ZXIoCiAgICAhaXMubmEobGF0aXR1ZGUpLAogICAgIShsb2NhdGlvbiAlaW4lIGZhY2lsaXRpZXMpCiAgICApICU+JQogIHN0X2FzX3NmKGNvb3JkcyA9IGMoImxvbmdpdHVkZSIsICJsYXRpdHVkZSIpLCBjcnMgPSA0MzI2KSAlPiUKICBzdF9qb2luKHN0X2FzX3NmKGhvb2RzKSwgam9pbiA9IHN0X3dpdGhpbiwgbGVmdCA9IEYpCgpjcmltZV9ob29kX2NvdW50cyA8LSBjcmltZV9sYWJlbGVkICU+JQogIGRhdGEuZnJhbWUoKSAlPiUKICBjb3VudChkZXNjcmlwdGlvbiwgbGFiZWwpICU+JQogIHNwcmVhZChrZXkgPSBkZXNjcmlwdGlvbiwgdmFsdWUgPSBuKSAlPiUKICByZXBsYWNlKGlzLm5hKC4pLCAwKSAlPiUKICB0cmFuc211dGUoCiAgICBsYWJlbCA9IGxhYmVsLAogICAgYWdnX2Fzc2F1bHQgPSBgQUdHLiBBU1NBVUxUYCwKICAgIHJhcGUgPSBSQVBFLAogICAgaG9taWNpZGVfc2hvb3RpbmdzID0gSE9NSUNJREUgKyBTSE9PVElORywKICAgIHJvYmJlcnkgPSBgUk9CQkVSWSAtIENPTU1FUkNJQUxgICsKICAgICAgYFJPQkJFUlkgLSBDQVJKQUNLSU5HYCArCiAgICAgIGBST0JCRVJZIC0gUkVTSURFTkNFYCArCiAgICAgIGBST0JCRVJZIC0gU1RSRUVUYCkgCmBgYAoKYGBge3J9CnNyX2xhYmVsZWQgPC0gc3IgJT4lCiAgZmlsdGVyKAogICAgIWlzLm5hKGxhdGl0dWRlKQogICAgKSAlPiUKICBzdF9hc19zZihjb29yZHMgPSBjKCJsb25naXR1ZGUiLCAibGF0aXR1ZGUiKSwgY3JzID0gNDMyNikgJT4lCiAgc3Rfam9pbihzdF9hc19zZihob29kcyksIGpvaW4gPSBzdF93aXRoaW4sIGxlZnQgPSBGKQoKc3JfaG9vZF9jb3VudHMgPC0gc3JfbGFiZWxlZCAlPiUKICBkYXRhLmZyYW1lKCkgJT4lCiAgY291bnQoc3J0eXBlLCBsYWJlbCkgJT4lCiAgc3ByZWFkKGtleSA9IHNydHlwZSwgdmFsdWUgPSBuKSAlPiUKICByZXBsYWNlKGlzLm5hKC4pLCAwKSAlPiUKICB0cmFuc211dGUoCiAgICBsYWJlbCA9IGxhYmVsLAogICAgaWxsZWdhbF9kdW1waW5nID0gYEhDRC1JbGxlZ2FsIER1bXBpbmdgICsgYFNXLVNJVSBDbGVhbiBVcGAsCiAgICBwcm9wZXJ0eV9tYWludGVuYW5jZSA9IGBIQ0QtU2FuaXRhdGlvbiBQcm9wZXJ0eWAgKwogICAgICBgU1ctQm9hcmRpbmdgICsKICAgICAgYFNXLUNsZWFuaW5nYCArCiAgICAgIGBTVy1IR1dgLAogICAgcmlnaHRfb2Zfd2F5ID0gYFNXLURpcnR5IFN0cmVldGAgKyBgU1ctRGlydHkgQWxsZXlgCiAgKQoKYGBgCgpgYGB7cn0KIyB0byBwZXIgMSwwMDAgcmVzaWRlbnRzCnRvX3Blcl9jYXBpdGEgPC0gZnVuY3Rpb24oeCl7MTAwMCAqIHggLyBob29kcyRBQ1NfMjAxM18yMDE3fQoKaG9vZF9tZXRyaWNzIDwtIGhvb2RzCgpob29kX21ldHJpY3NAZGF0YSA8LSBob29kX21ldHJpY3NAZGF0YSAlPiUKICBzZWxlY3QoLWFjcmVzLAogICAgICAgICAtbmJyZGVzYywKICAgICAgICAgLXNoYXBlX2xlbmcsCiAgICAgICAgIC1zaGFwZV9hcmVhLAogICAgICAgICAtY29sb3JfMiwKICAgICAgICAgLURlY2VubmlhbDIwMTApCgpob29kX21ldHJpY3NAZGF0YSA8LSBob29kX21ldHJpY3NAZGF0YSAlPiUKICBsZWZ0X2pvaW4oCiAgICBjcmltZV9ob29kX2NvdW50cywKICAgIGJ5ID0gImxhYmVsIikgJT4lCiAgbGVmdF9qb2luKAogICAgc3JfaG9vZF9jb3VudHMsCiAgICBieSA9ICJsYWJlbCIKICApICU+JQogIG11dGF0ZV9hdCgKICAgIHZhcnMoCiAgICAgIGlsbGVnYWxfZHVtcGluZywKICAgICAgcHJvcGVydHlfbWFpbnRlbmFuY2UsCiAgICAgIHJpZ2h0X29mX3dheSwKICAgICAgaG9taWNpZGVfc2hvb3RpbmdzLAogICAgICByb2JiZXJ5LAogICAgICBhZ2dfYXNzYXVsdCwKICAgICAgcmFwZSksCiAgICBsaXN0KHBlcl8xMDAwX3JlcyA9IHRvX3Blcl9jYXBpdGEpKQpgYGAKCkRpc3RyaWJ1dGlvbiBvZiBwZXIgY2FwaXRhIHJhdGVzIG9mIGNyaW1lIGFuZCBzZXJ2aWNlIHJlcXVlc3RzOgoKYGBge3J9Cmhvb2RfbWV0cmljc0BkYXRhICU+JQogIHNlbGVjdCgKICAgIGxhYmVsLAogICAgaWxsZWdhbF9kdW1waW5nX3Blcl8xMDAwX3JlcywKICAgIHByb3BlcnR5X21haW50ZW5hbmNlX3Blcl8xMDAwX3JlcywKICAgIHJpZ2h0X29mX3dheV9wZXJfMTAwMF9yZXMsCiAgICBob21pY2lkZV9zaG9vdGluZ3NfcGVyXzEwMDBfcmVzLAogICAgcm9iYmVyeV9wZXJfMTAwMF9yZXMsCiAgICBhZ2dfYXNzYXVsdF9wZXJfMTAwMF9yZXMsCiAgICByYXBlX3Blcl8xMDAwX3JlcwogICkgJT4lCiAgcGl2b3RfbG9uZ2VyKC1sYWJlbCkgJT4lCiAgZ2dwbG90KGFlcyh2YWx1ZSkpICsKICBmYWNldF93cmFwKH5uYW1lLCBzY2FsZXMgPSAiZnJlZSIpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gNTApICsKICB0aGVtZV9pdGVhbV9nb29nbGVfZG9jcygpICsKICBsYWJzKHRpdGxlID0gIjIwMTkgRXZlbnRzIHBlciAxLDAwMCBSZXNpZGVudHMiKQpgYGAKCkluIGFsbCBjYXNlcywgb3V0bGllciBuZWlnaGJvcmhvb2RzIHdpdGggdmVyeSBzbWFsbCBwb3B1bGF0aW9ucyBza2V3IGRhdGEuIAoKVHJ5IHJlbW92aW5nIG5laWdoYm9yaG9vZHMgd2l0aCBsZXNzIHRoYW4gMTUwIHJlc2lkZW50cyAoMTAlIG9mIG5laWdoYm9yaG9vZHMpLiBUaGVzZSBhcmUgdHlwaWNhbGx5IHBhcmtzLCBpbmR1c3RyaWFsIGFyZWFzLCBldGMuCgpgYGB7cn0KaG9vZF9tZXRyaWNzQGRhdGEgJT4lCiAgZmlsdGVyKEFDU18yMDEzXzIwMTcgPj0gMTUwKSAlPiUKICBzZWxlY3QoCiAgICBsYWJlbCwKICAgIGlsbGVnYWxfZHVtcGluZ19wZXJfMTAwMF9yZXMsCiAgICBwcm9wZXJ0eV9tYWludGVuYW5jZV9wZXJfMTAwMF9yZXMsCiAgICByaWdodF9vZl93YXlfcGVyXzEwMDBfcmVzLAogICAgaG9taWNpZGVfc2hvb3RpbmdzX3Blcl8xMDAwX3JlcywKICAgIHJvYmJlcnlfcGVyXzEwMDBfcmVzLAogICAgYWdnX2Fzc2F1bHRfcGVyXzEwMDBfcmVzLAogICAgcmFwZV9wZXJfMTAwMF9yZXMKICApICU+JQogIHBpdm90X2xvbmdlcigtbGFiZWwpICU+JQogIGdncGxvdChhZXModmFsdWUpKSArCiAgZmFjZXRfd3JhcCh+bmFtZSwgc2NhbGVzID0gImZyZWUiKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDUwKSArCiAgICB0aGVtZV9pdGVhbV9nb29nbGVfZG9jcygpICsKICBsYWJzKHRpdGxlID0gIjIwMTkgRXZlbnRzIHBlciAxLDAwMCBSZXNpZGVudHNcbk5laWdoYm9yaG9vZHMgd2l0aCA+PSAxNTAgUmVzaWRlbnRzIikKYGBgCgpHb2luZyBmb3J3YXJkLCByZW1vdmluZyBuZWlnaGJvcmhvb2RzIHdpdGggbGVzcyB0aGFuIDE1MCByZXNpZGVudHMuCgpgYGB7cn0KaG9vZF9tZXRyaWNzX292ZXIxNTAgPC0gc3Vic2V0KGhvb2RfbWV0cmljcywgaG9vZF9tZXRyaWNzJEFDU18yMDEzXzIwMTcgPiAxNTApCmhvb2RfbWV0cmljc19vdmVyMTUwIDwtIHN1YnNldChob29kX21ldHJpY3Nfb3ZlcjE1MCwgIWdyZXBsKCJJTkRVU1RSSUFMIiwgbGFiZWwsIGlnbm9yZS5jYXNlID0gVCkpCmBgYAoKTnVtYmVyIG9mIG5laWdoYm9yaG9vZHMgd2l0aCBhdCBsZWFzdCBvbmUgaG9taWNpZGUgb3Igc2hvb3Rpbmc6CgpgYGB7cn0KaG9vZF9tZXRyaWNzX292ZXIxNTBAZGF0YSAlPiUKICBjb3VudChob21pY2lkZV9zaG9vdGluZ3MgPj0gMSkKYGBgCgpXaWxsIGxpa2VseSBhc3NpZ24gMSB0byBuZWlnaGJvcmhvb2RzIHdpdGggYXQgbGVhc3QgMSBob21pY2lkZSBvciBzaG9vdGluZywgMCB0byBhbGwgb3RoZXJzLiBUaGlzIHdpbGwgZW5zdXJlIG5laWdoYm9yaG9vZHMgd2l0aCBndW4gdmlvbGVuY2UgYXJlIGdpdmVuIHByZWNlZGVuY2UuCgojIEJ1aWxkaW5nIFRoZSBJbmRleAoKQWxsIHBhcmFtZXRlcnMgd2lsbCBiZSBzY2FsZWQgdG8gYmV0d2VlbiAwIGFuZCAxIGJlY2F1c2UgdmFyaWFibGVzIGFyZSBvbiBkaWZmZXJlbnQgc2NhbGVzLgoKYGBge3J9CiMgc2NhbGUgcGVyIGNhcGl0YQpzY2FsZV9pbmRleCA8LSBmdW5jdGlvbih4KXtyZXNjYWxlKHgsIHRvID0gYygwLDEpKX0KCmhvb2RfbWV0cmljc19vdmVyMTUwQGRhdGEgPC0gaG9vZF9tZXRyaWNzX292ZXIxNTBAZGF0YSAlPiUKICBtdXRhdGUoCiAgICBob21pY2lkZV9zaG9vdGluZ3NfaW5kZXggPSBpZmVsc2UoaG9taWNpZGVfc2hvb3RpbmdzID4gMCwgMSwgMCksCiAgICByYXBlX2luZGV4ID0gaWZlbHNlKHJhcGUgPiAwLCAxLCAwKSkgJT4lCiAgbXV0YXRlX2F0KAogICAgdmFycygKICAgICAgaWxsZWdhbF9kdW1waW5nX3Blcl8xMDAwX3JlcywKICAgICAgcHJvcGVydHlfbWFpbnRlbmFuY2VfcGVyXzEwMDBfcmVzLAogICAgICByaWdodF9vZl93YXlfcGVyXzEwMDBfcmVzLAogICAgICBob21pY2lkZV9zaG9vdGluZ3NfcGVyXzEwMDBfcmVzLAogICAgICByb2JiZXJ5X3Blcl8xMDAwX3JlcywKICAgICAgYWdnX2Fzc2F1bHRfcGVyXzEwMDBfcmVzLAogICAgICByYXBlX3Blcl8xMDAwX3JlcyksCiAgICBsaXN0KGluZGV4ID0gc2NhbGVfaW5kZXgpCiAgICApIApgYGAKCmBgYHtyfQojIHBsb3QgcmVzY2FsZWQgZGF0YQpob29kX21ldHJpY3Nfb3ZlcjE1MEBkYXRhICU+JQogIHNlbGVjdCgKICAgIGxhYmVsLAogICAgaWxsZWdhbF9kdW1waW5nX3Blcl8xMDAwX3Jlc19pbmRleCwKICAgIHByb3BlcnR5X21haW50ZW5hbmNlX3Blcl8xMDAwX3Jlc19pbmRleCwKICAgIHJpZ2h0X29mX3dheV9wZXJfMTAwMF9yZXNfaW5kZXgsCiAgICBob21pY2lkZV9zaG9vdGluZ3NfcGVyXzEwMDBfcmVzX2luZGV4LAogICAgcm9iYmVyeV9wZXJfMTAwMF9yZXNfaW5kZXgsCiAgICBhZ2dfYXNzYXVsdF9wZXJfMTAwMF9yZXNfaW5kZXgsCiAgICByYXBlX3Blcl8xMDAwX3Jlc19pbmRleAogICkgJT4lCiAgcGl2b3RfbG9uZ2VyKC1sYWJlbCkgJT4lCiAgZ2dwbG90KGFlcyh2YWx1ZSkpICsKICBmYWNldF93cmFwKH5uYW1lLCBzY2FsZXMgPSAiZnJlZSIpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gNTApICsKICAgIHRoZW1lX2l0ZWFtX2dvb2dsZV9kb2NzKCkgKwogIGxhYnModGl0bGUgPSAiU3RhbmRhcmRpemVkIChiZXR3ZWVuIDAgYW5kIDEpIDIwMTkgRXZlbnRzIHBlciAxLDAwMCBSZXNpZGVudHNcbk5laWdoYm9yaG9vZHMgd2l0aCA+PSAxNTAgUmVzaWRlbnRzIikKYGBgCgoqKkFnYWluLCBhbGwgbWV0cmljcyBoYXZlIGJlZW4gc2NhbGVkIHRvIGJldHdlZW4gMCBhbmQgMS4qKiBDb21iaW5lIGNyaW1lIG1ldHJpY3MgaW50byBhIGhvbWljaWRlIGFuZCBzaG9vdGluZyBwYXJhbWV0ZXIgKDAgaWYgbm9uZSBpbiBuZWlnaGJvcmhvb2QsIDEgaWYgYXQgbGVhc3QgMSkgYW5kIGFuICJvdGhlciB2aW9sZW50IGNyaW1lIiBwYXJhbWV0ZXIgd2hlcmU6CgokJCBIb21pY2lkZVNob290aW5nc0luZGV4ID0gXGJlZ2lue2Nhc2VzfQoxICYgXHRleHR7aWYgJE5fe2hvbWljaWRlc30rTl97c2hvb3RpbmdzfSA+IDAkIH0gXFwgCjAgJiBcdGV4dHtvdGhlcndpc2V9IFxlbmR7Y2FzZXN9JCQKCiQkIE90aGVyVmlvbGVudENyaW1lSW5kZXggPSBcZnJhY3sxfXszfShSYXBlSW5kZXgrIEFnZ0Fzc2F1bHRJbmRleCArIFJvYmJlcnlJbmRleCkgJCQKCkNvbWJpbmluZyB0aGUgdHdvIGNyaW1lIGluZGljZXM6CgokJCBDcmltZUluZGV4ID0gXGZyYWN7MX17Mn0gKEhvbWljaWRlU2hvb3RpbmdzSW5kZXggKyBPdGhlclZpb2xlbnRDcmltZUluZGV4KSAkJApgYGB7cn0KIyBjcmVhdGUgY29tYmluZWQgaW5kZXgKaG9vZF9tZXRyaWNzX292ZXIxNTBAZGF0YSA8LSBob29kX21ldHJpY3Nfb3ZlcjE1MEBkYXRhICU+JQogIHJvd3dpc2UoKSAlPiUKICBtdXRhdGUoCiAgICBvdGhlcl92aW9sZW50X2NyaW1lX2luZGV4ID0gCiAgICAgIG1lYW4oCiAgICAgICAgYyhyYXBlX3Blcl8xMDAwX3Jlc19pbmRleCwKICAgICAgICAgIGFnZ19hc3NhdWx0X3Blcl8xMDAwX3Jlc19pbmRleCwgCiAgICAgICAgICByb2JiZXJ5X3Blcl8xMDAwX3Jlc19pbmRleCksIAogICAgICAgIG5hLnJtID0gVCksCiAgICBncmltZV9pbmRleCA9IG1lYW4oCiAgICAgIGMoaWxsZWdhbF9kdW1waW5nX3Blcl8xMDAwX3Jlc19pbmRleCwKICAgICAgICBwcm9wZXJ0eV9tYWludGVuYW5jZV9wZXJfMTAwMF9yZXNfaW5kZXgsCiAgICAgICAgcmlnaHRfb2Zfd2F5X3Blcl8xMDAwX3Jlc19pbmRleCksCiAgICAgIG5hLnJtID0gVCkKICApICU+JQogIHVuZ3JvdXAoKSAlPiUKICBtdXRhdGUoY3JpbWVfaW5kZXggPSAwLjUgKiBob21pY2lkZV9zaG9vdGluZ3NfcGVyXzEwMDBfcmVzX2luZGV4ICsgCiAgICAgICAgICAgMC41ICogb3RoZXJfdmlvbGVudF9jcmltZV9pbmRleCwKICAgICAgICAgY3JpbWVfZ3JpbWVfaW5kZXggPSAoMi8zKSAqIGNyaW1lX2luZGV4ICsgKDEvMykgKiBncmltZV9pbmRleCwKICAgICAgICAgY3JpbWVfZ3JpbWVfaW5kZXhfcXVhZHJhdHVyZSA9IHNxcnQoY3JpbWVfaW5kZXheMiArIGdyaW1lX2luZGV4XjIpKQpgYGAKCk5vdyBjcmVhdGluZyB0aGUgImdyaW1lIiBpbmRleDoKCiQkIEdyaW1lSW5kZXggPSBcZnJhY3sxfXszfShJbGxlZ2FsRHVtcGluZ0luZGV4ICsgUHJvcE1haW50ZW5hbmNlSW5kZXggKyBSaWdodE9mV2F5SW5kZXgpICQkCkNvbWJpbmUgaW50byBhIHNpbmdsZSBpbmRleC4gQ3JpbWUgd2VpZ2h0ZWQgbW9yZSBoZWF2aWx5LgoKJCQgQ3JpbWVHcmltZUluZGV4ID0gXGZyYWN7Mn17M31DcmltZUluZGV4ICsgXGZyYWN7MX17M31HcmltZUluZGV4ICQkCgojIEp1c3QgU2hvdyBNZSBUaGUgUmVzdWx0cwoKYGBge3IgZmlnLmhlaWdodCA9IDgsIGZpZy53aWR0aCA9IDh9CiMgYmFzZV9tYXAgPC0gZ2V0X21hcCgKIyAgIGxvY2F0aW9uPWMobG9uID0gLTc2LjYxLCBsYXQgPSAzOS4zKSwgCiMgICB6b29tPTEyLCAKIyAgIG1hcHR5cGUgPSAndG9uZXItbGl0ZScsIAojICAgc291cmNlID0gJ3N0YW1lbicKIyAgICkKIyAKIyBnZ21hcChiYXNlX21hcCkgKwojICAgIyBnZW9tX3BvaW50KAojICAgIyAgIGRhdGEgPSByZXBlYXRfb2ZmZW5kZXJfbG9jYXRpb25zICU+JQojICAgIyAgICAgZmlsdGVyKCFpcy5uYShsb24pLAojICAgIyAgICAgICAgICAgIG4gPj0gMyksCiMgICAjICAgYWVzKHggPSBsb24sIHkgPSBsYXQpLAojICAgIyAgIGNvbG9yID0gImJsdWUiLAojICAgIyAgIHNpemUgPSAyCiMgICAjICkgIAojICAgZ2VvbV9wb2x5Z29uKAojICAgICBkYXRhID0gZm9ydGlmeShob29kX21ldHJpY3Nfb3ZlcjE1MCkgJT4lCiMgICAgICAgZmlsdGVyKCFpcy5uYShjcmltZV9ncmltZV9pbmRleCkpLAojICAgICBhZXMoeCA9IGxvbmcsIHkgPSBsYXQsIGdyb3VwID0gZ3JvdXAsIGZpbGwgPSBjcmltZV9ncmltZV9pbmRleCksIAojICAgICBhbHBoYSA9IDAuOSxjb2xvciA9ICJibGFjayIKIyAgICkjICsKIyAgICMgc2NhbGVfZmlsbF92aXJpZGlzX2MobmEudmFsdWUgPSBOQSwgCiMgICAjICAgICAgICAgICAgICAgICAgICAgICN2YWx1ZXMgPSByZXNjYWxlKGMoMCwgMjAsIDcwKSwgYygwLDEpKSwKIyAgICMgICAgICAgICAgICAgICAgICAgICAgb3B0aW9uID0gInBsYXNtYSIsCiMgICAjICAgICAgICAgICAgICAgICAgICAgIGd1aWRlX2NvbG9yYmFyKHRpdGxlID0gIkFubnVhbCBEViBJbmNpZGVudHNcbnBlciAxLDAwMCBSZXNpZGVudHMiKSkKIyAgICMgCmBgYAoKYGBge3J9Cmhvb2RzQGRhdGEgPC0gaG9vZHNAZGF0YSAlPiUKICBsZWZ0X2pvaW4oCiAgICBob29kX21ldHJpY3Nfb3ZlcjE1MEBkYXRhICU+JSBzZWxlY3QoLUFDU18yMDEzXzIwMTcpLAogICAgYnkgPSAibGFiZWwiCiAgKQpgYGAKCgpgYGB7cn0KIyBjb2xvciBwYWxldHRlIGZvciBtYXAKcGFsIDwtICBjb2xvck51bWVyaWMoInZpcmlkaXMiLCAKICAgICAgICAgICAgICAgICAgICAgZG9tYWluID0gaG9vZHMkY3JpbWVfZ3JpbWVfaW5kZXgsCiAgICAgICAgICAgICAgICAgICAgIG5hLmNvbG9yID0gInRyYW5zcGFyZW50IikKCiMgbGFiZWxzCmhvb2RzQGRhdGEgPC0gaG9vZHNAZGF0YSAlPiUKICBtdXRhdGUobWFwX2xhYmVsID0gcGFzdGUwKAogICAgIjxiPiIsaG9vZHMkbGFiZWwsICI8L2I+PGJyPiIsCiAgICAiUG9wdWxhdGlvbjogIiwgcm91bmQoaG9vZHMkQUNTXzIwMTNfMjAxNywgMCksICI8YnI+IiwKICAgICJDcmltZSAmIEdyaW1lIEluZGV4OiAiLCByb3VuZChob29kcyRjcmltZV9ncmltZV9pbmRleCwgMiksICI8YnI+IiwKICAgICJDcmltZSBJbmRleDogIiwgcm91bmQoaG9vZHMkY3JpbWVfaW5kZXgsIDIpLCAiPGJyPiIsCiAgICAiR3JpbWUgSW5kZXg6ICIsIHJvdW5kKGhvb2RzJGdyaW1lX2luZGV4LCAyKSwgIjxicj4iLAogICAgIjxicj48Yj4yMDE5IENyaW1lPC9iPjxicj4iLAogICAgIkhvbWljaWRlcyArIFNob290aW5nczogIiwgaG9vZHMkaG9taWNpZGVfc2hvb3RpbmdzLCAiPGJyPiIsCiAgICAiUmFwZTogIiwgaG9vZHMkcmFwZSwgIjxicj4iLAogICAgIkFnZ3JhdmF0ZWQgQXNzYXVsdDogIiwgaG9vZHMkYWdnX2Fzc2F1bHQsICI8YnI+IiwKICAgICJSb2JiZXJ5OiAiLCBob29kcyRyb2JiZXJ5LCAiPGJyPiIsCiAgICAiPGJyPjxiPjIwMTkgU2VydmljZSBSZXF1ZXN0czwvYj48YnI+IiwKICAgICJJbGxlZ2FsIER1bXBpbmcgU1JzOiAiLCBob29kcyRpbGxlZ2FsX2R1bXBpbmcsICI8YnI+IiwKICAgICJQcm9wZXJ0eSBNYWludGVuYW5jZSBTUnM6ICIsIGhvb2RzJHByb3BlcnR5X21haW50ZW5hbmNlLCAiPGJyPiIsCiAgICAiUmlnaHQtb2YtV2F5IFNSczogIiwgaG9vZHMkcmlnaHRfb2Zfd2F5LCAiPGJyPiIKKSkKYGBgCgpgYGB7ciBmaWcud2lkdGggPSA4LCBmaWcuaGVpZ2h0ID0gNn0KbGVhZmxldCgpICU+JQogIHNldFZpZXcobG5nID0gLTc2LjYsIGxhdCA9IDM5LjMsIHpvb20gPSAxMSkgJT4lCiAgYWRkUHJvdmlkZXJUaWxlcyhwcm92aWRlcnMkU3RhbWVuLlRvbmVyTGl0ZSkgJT4lIAogIGFkZFBvbHlnb25zKGRhdGEgPSBob29kcywKICAgICAgICAgICAgICB3ZWlnaHQgPSAyLAogICAgICAgICAgICAgIGZpbGxDb2xvciAgPSB+cGFsKGhvb2RzJGNyaW1lX2dyaW1lX2luZGV4KSwKICAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsCiAgICAgICAgICAgICAgb3BhY2l0eSA9IDAuOSwKICAgICAgICAgICAgICBmaWxsT3BhY2l0eSA9IDAuNzUsCiAgICAgICAgICAgICAgbGFiZWwgPSBob29kcyRsYWJlbCwKICAgICAgICAgICAgICBwb3B1cCA9IH5sYXBwbHkoaG9vZHMkbWFwX2xhYmVsLCBIVE1MKSwKICAgICAgICAgICAgICBsYWJlbE9wdGlvbnMgPSBsYWJlbE9wdGlvbnMobm9IaWRlID0gRiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICN0ZXh0T25seSA9IFQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9ICdyaWdodCcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRleHRzaXplID0gMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3BhY2l0eSA9IDEpKSAlPiUKICBhZGRDb250cm9sKCJCYWx0aW1vcmU8YnI+Q3JpbWUgJiBHcmltZSBJbmRleDxicj48YnI+Q2xpY2sgTmVpZ2hib3Job29kPGJyPkZvciBNb3JlIEluZm8iLAogICAgICAgICAgICAgcG9zaXRpb24gPSAidG9wbGVmdCIpICU+JQogIGFkZExlZ2VuZChwYWwgPSBwYWwsIHZhbHVlcyA9IGhvb2RzJGNyaW1lX2dyaW1lX2luZGV4LCBwb3NpdGlvbiA9ICJib3R0b21yaWdodCIsCiAgICAgICAgICAgIHRpdGxlID0gIkNyaW1lIEdyaW1lIEluZGV4IikKYGBgCgojIyBEaXN0cmlidXRpb24gb2YgSW5kZXhlcwoKQmVjYXVzZSBvZiB0aGUgaG9taWNpZGUgYW5kIHNob290aW5nIGluZGV4IGJlaW5nIDEgZm9yIG5laWdoYm9yaG9vZHMgd2l0aCBhdCBsZWFzdCBvbmUgaG9taWNpZGUgb3Igc2hvb3RpbmcgYW5kIDAgZm9yIGFsbCBvdGhlcnMsIHRoZSBkaXN0cmlidXRpb24gaXMgYmlmdXJjYXRlZCBpbnRvIG5laWdoYm9yaG9vZHMgd2l0aCBhbmQgd2l0aG91dCBzaG9vdGluZ3MuCgpgYGB7ciwgZmlnLmhlaWdodCA9IDEsIGZpZy53aWR0aCA9IDJ9Cmhvb2RzQGRhdGEgJT4lCiAgZ2dwbG90KGFlcyhjcmltZV9ncmltZV9pbmRleCkpICsKICBnZW9tX2hpc3RvZ3JhbSgpICsKICB0aGVtZV9pdGVhbV9nb29nbGVfZG9jcygpIApgYGAKCiMjIFRoZSBMaXN0LCBJbiBPcmRlciBvZiBEZXNjZW5kaW5nIENyaW1lLUdyaW1lIEluZGV4CgpTb21lIG5laWdoYm9yaG9vZHMgd2l0aCB2ZXJ5IHNtYWxsIHBvcHVsYXRpb25zIHN0aWxsIHNuZWFrIG9udG8gdGhlIGxpc3QgYmVjYXVzZSB3ZSBvbmx5IHVzZWQgMTUwIGFzIHRoZSBjdXQtb2ZmLCBidXQgdGhvc2UgY2FuIGJlIG1hbnVhbGx5IGRyb3BwZWQgaWYgbm90IGludGVyZXN0ZWQuCgpgYGB7cn0KaG9vZHNAZGF0YSAlPiUKICBhcnJhbmdlKGRlc2Mocm9iYmVyeV9wZXJfMTAwMF9yZXMpKSAlPiUKICBzZWxlY3QoLWFjcmVzLCAtbmJyZGVzYywgLXNoYXBlX2xlbmcsIC1zaGFwZV9hcmVhLCAtY29sb3JfMiwgLURlY2VubmlhbDIwMTApICU+JQogIHJlbmFtZShuZWlnaGJvcmhvb2QgPSBsYWJlbCwKICAgICAgICAgcG9wdWxhdGlvbl9hY3NfMjAxM18yMDE3ID0gQUNTXzIwMTNfMjAxNykKCiN3cml0ZV9jc3YodGhlX2xpc3QsICIuLi9kYXRhL3Byb2Nlc3NlZC9jcmltZV9ncmltZV9pbmRleF92My5jc3YiKQoKCmBgYAoKYGBge3J9CnRvcF8yMCA8LSBob29kcyAlPiUKICBhcnJhbmdlKGRlc2MoY3JpbWVfZ3JpbWVfaW5kZXgpKSAlPiUKICB0b3BfbihuID0gMjAsIHd0ID0gY3JpbWVfZ3JpbWVfaW5kZXgpCmBgYAoKYGBge3J9CmNvbG9yX2xpc3QgPC0gaG9vZHNAZGF0YSAlPiUKICBhcnJhbmdlKGRlc2MoY3JpbWVfZ3JpbWVfaW5kZXgpKSAlPiUKICBtdXRhdGUodG9wMjBfY29sb3IgPSBpZmVsc2Uocm93X251bWJlcigpIDw9IDIwLCBpdGVhbS5jb2xvcnNbMV0sIE5BKSkgJT4lCiAgc2VsZWN0KGxhYmVsLCB0b3AyMF9jb2xvcikKCmhvb2RzQGRhdGEgPC0gaG9vZHNAZGF0YSAlPiUKICBsZWZ0X2pvaW4oY29sb3JfbGlzdCwgYnkgPSAibGFiZWwiKQpgYGAKCiMgVG9wIDIwIE5laWdoYm9yaG9vZHMKCmBgYHtyIGZpZy53aWR0aCA9IDgsIGZpZy5oZWlnaHQgPSA2fQpmaWxsX3BhbCA8LSBjb2xvckZhY3Rvcihob29kcyR0b3AyMF9jb2xvciwgaG9vZHMkdG9wMjBfY29sb3IsIG5hLmNvbG9yID0gInRyYW5zcGFyZW50IikKCmxlYWZsZXQoKSAlPiUKICBzZXRWaWV3KGxuZyA9IC03Ni42LCBsYXQgPSAzOS4zLCB6b29tID0gMTEpICU+JQogIGFkZFByb3ZpZGVyVGlsZXMocHJvdmlkZXJzJFN0YW1lbi5Ub25lckxpdGUpICU+JSAKICBhZGRQb2x5Z29ucyhkYXRhID0gaG9vZHMsCiAgICAgICAgICAgICAgd2VpZ2h0ID0gMiwKICAgICAgICAgICAgICBmaWxsQ29sb3IgID0gfmZpbGxfcGFsKGhvb2RzJHRvcDIwX2NvbG9yKSwKICAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsCiAgICAgICAgICAgICAgb3BhY2l0eSA9IDAuOSwKICAgICAgICAgICAgICBmaWxsT3BhY2l0eSA9IDAuNzUsCiAgICAgICAgICAgICAgbGFiZWwgPSBob29kcyRsYWJlbCwKICAgICAgICAgICAgICBwb3B1cCA9IH5sYXBwbHkoaG9vZHMkbWFwX2xhYmVsLCBIVE1MKSwKICAgICAgICAgICAgICBsYWJlbE9wdGlvbnMgPSBsYWJlbE9wdGlvbnMobm9IaWRlID0gRiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICN0ZXh0T25seSA9IFQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9ICdyaWdodCcsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRleHRzaXplID0gMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3BhY2l0eSA9IDEpKSAlPiUKICBhZGRDb250cm9sKCJCYWx0aW1vcmU8YnI+Q3JpbWUgJiBHcmltZSBJbmRleDxicj5Ub3AgMjAgTmVpZ2hib3Job29kczxicj48YnI+Q2xpY2sgTmVpZ2hib3Job29kPGJyPkZvciBNb3JlIEluZm8iLCAKICAgICAgICAgICAgIHBvc2l0aW9uID0gInRvcGxlZnQiKQpgYGAKCiMgQ3JpbWUgdi4gR3JpbWUKUmVkIG1lYW5zIHRoZSBjcmltZSBpbmRleCB3YXMgaGlnaGVyLCBibHVlIG1lYW5zIHRoZSBncmltZSBpbmRleCB3YXMgaGlnaGVyLgoKYGBge3J9Cmhvb2RzQGRhdGEgPC0gaG9vZHNAZGF0YSAlPiUgbXV0YXRlKGNyaW1lX2dyaW1lX2luZGV4X2RpZmYgPSBjcmltZV9pbmRleCAtIGdyaW1lX2luZGV4KQpgYGAKCgpgYGB7ciBmaWcud2lkdGggPSA4LCBmaWcuaGVpZ2h0ID0gNn0KZGlmZl9wYWwgPC0gIGNvbG9yTnVtZXJpYygiUmRCdSIsIAogICAgICAgICAgICAgICAgICAgICBkb21haW4gPSBob29kcyRjcmltZV9ncmltZV9pbmRleF9kaWZmLAogICAgICAgICAgICAgICAgICAgICBuYS5jb2xvciA9ICJ0cmFuc3BhcmVudCIsIHJldmVyc2UgPSBUKQoKbGVhZmxldCgpICU+JQogIHNldFZpZXcobG5nID0gLTc2LjYsIGxhdCA9IDM5LjMsIHpvb20gPSAxMSkgJT4lCiAgYWRkUHJvdmlkZXJUaWxlcyhwcm92aWRlcnMkU3RhbWVuLlRvbmVyTGl0ZSkgJT4lIAogIGFkZFBvbHlnb25zKGRhdGEgPSBob29kcywKICAgICAgICAgICAgICB3ZWlnaHQgPSAyLAogICAgICAgICAgICAgIGZpbGxDb2xvciAgPSB+ZGlmZl9wYWwoaG9vZHMkY3JpbWVfZ3JpbWVfaW5kZXhfZGlmZiksCiAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgIG9wYWNpdHkgPSAwLjksCiAgICAgICAgICAgICAgZmlsbE9wYWNpdHkgPSAwLjc1LAogICAgICAgICAgICAgIGxhYmVsID0gaG9vZHMkbGFiZWwsCiAgICAgICAgICAgICAgcG9wdXAgPSB+bGFwcGx5KGhvb2RzJG1hcF9sYWJlbCwgSFRNTCksCiAgICAgICAgICAgICAgbGFiZWxPcHRpb25zID0gbGFiZWxPcHRpb25zKG5vSGlkZSA9IEYsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjdGV4dE9ubHkgPSBULAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAncmlnaHQnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZXh0c2l6ZSA9IDIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9wYWNpdHkgPSAxKSkgJT4lCiAgYWRkQ29udHJvbCgiQmFsdGltb3JlPGJyPkNyaW1lICYgR3JpbWUgSW5kZXg8YnI+Q3JpbWUtR3JpbWUgRGlmZmVyZW5jZTxicj48YnI+Q2xpY2sgTmVpZ2hib3Job29kPGJyPkZvciBNb3JlIEluZm8iLCAKICAgICAgICAgICAgIHBvc2l0aW9uID0gInRvcGxlZnQiKSAlPiUKICBhZGRMZWdlbmQocGFsID0gZGlmZl9wYWwsIHZhbHVlcyA9IGhvb2RzJGNyaW1lX2dyaW1lX2luZGV4X2RpZmYsIHBvc2l0aW9uID0gImJvdHRvbXJpZ2h0IiwgdGl0bGUgPSAiUmVkOiBNb3JlIENyaW1lPGJyPkJsdWU6IE1vcmUgR3JpbWUiKQpgYGAKCgoKYGBge3J9Cmhvb2RzQGRhdGEgJT4lCiAgZmlsdGVyKGxhYmVsICVpbiUgYygiTWlsdG9uLU1vbnRmb3JkIiwKICAgICAgICAgICAgICAgICAgICAgICJDYXJyb2xsdG9uIFJpZGdlIiwKICAgICAgICAgICAgICAgICAgICAgICJQZW5uIE5vcnRoIiwKICAgICAgICAgICAgICAgICAgICAgICJCcm9hZHdheSBFYXN0IiwKICAgICAgICAgICAgICAgICAgICAgICJEb3dudG93biIpKSAlPiUKICBhcnJhbmdlKGRlc2Mocm9iYmVyeV9wZXJfMTAwMF9yZXMpKSAlPiUKICBzZWxlY3QoLWFjcmVzLCAtbmJyZGVzYywgLXNoYXBlX2xlbmcsIC1zaGFwZV9hcmVhLCAtY29sb3JfMiwgLURlY2VubmlhbDIwMTApICU+JQogIHJlbmFtZShuZWlnaGJvcmhvb2QgPSBsYWJlbCwKICAgICAgICAgcG9wdWxhdGlvbl9hY3NfMjAxM18yMDE3ID0gQUNTXzIwMTNfMjAxNykgCmBgYAoKYGBge3IgZmlnLndpZHRoID0gMTIsIGZpZy5oZWlnaHQgPSA2fQpob29kc0BkYXRhICU+JQogIGZpbHRlcihsYWJlbCAlaW4lIGMoIk1pbHRvbi1Nb250Zm9yZCIsCiAgICAgICAgICAgICAgICAgICAgICAiQ2Fycm9sbHRvbiBSaWRnZSIsCiAgICAgICAgICAgICAgICAgICAgICAiUGVubiBOb3J0aCIsCiAgICAgICAgICAgICAgICAgICAgICAiQnJvYWR3YXkgRWFzdCIsCiAgICAgICAgICAgICAgICAgICAgICAiRG93bnRvd24iKSkgJT4lCiAgc2VsZWN0KAogICAgbGFiZWwsCiAgICBpbGxlZ2FsX2R1bXBpbmdfcGVyXzEwMDBfcmVzLAogICAgcHJvcGVydHlfbWFpbnRlbmFuY2VfcGVyXzEwMDBfcmVzLAogICAgcmlnaHRfb2Zfd2F5X3Blcl8xMDAwX3JlcywKICAgIGhvbWljaWRlX3Nob290aW5nc19wZXJfMTAwMF9yZXMsCiAgICByb2JiZXJ5X3Blcl8xMDAwX3JlcywKICAgIGFnZ19hc3NhdWx0X3Blcl8xMDAwX3JlcywKICAgIHJhcGVfcGVyXzEwMDBfcmVzKSAlPiUKICBwaXZvdF9sb25nZXIoLWxhYmVsKSAlPiUKICBnZ3Bsb3QoYWVzKGxhYmVsLCB2YWx1ZSkpICsKICBmYWNldF93cmFwKH5uYW1lLCBzY2FsZXMgPSAiZnJlZSIpICsgCiAgZ2VvbV9jb2woKSArCiAgY29vcmRfZmxpcCgpICsKICB0aGVtZV9pdGVhbV9nb29nbGVfZG9jcygpIApgYGAKCmBgYHtyIGZpZy53aWR0aCA9IDcsIGZpZy5oZWlnaHQgPSA3fQpob29kc0BkYXRhICU+JQogIGZpbHRlcihsYWJlbCAlaW4lIGMoIk1pbHRvbi1Nb250Zm9yZCIsCiAgICAgICAgICAgICAgICAgICAgICAiQ2Fycm9sbHRvbiBSaWRnZSIsCiAgICAgICAgICAgICAgICAgICAgICAiUGVubiBOb3J0aCIsCiAgICAgICAgICAgICAgICAgICAgICAiQnJvYWR3YXkgRWFzdCIpKSAlPiUKICB0cmFuc211dGUoCiAgICBOZWlnaGJvcmhvb2QgPSBsYWJlbCwKICAgIGBJbGxlZ2FsIER1bXBpbmcgU1JzIHBlciAxLDAwMCBSZXNpZGVudHNgID0gaWxsZWdhbF9kdW1waW5nX3Blcl8xMDAwX3JlcywKICAgIGBQcm9wLiAgTWFpbnRlbmFuY2UgU1JzIHBlciAxLDAwMCBSZXNpZGVudHNgID0gcHJvcGVydHlfbWFpbnRlbmFuY2VfcGVyXzEwMDBfcmVzLAogICAgYFJpZ2h0IG9mIFdheSBTUnMgcGVyIDEsMDAwIFJlc2lkZW50c2AgPSByaWdodF9vZl93YXlfcGVyXzEwMDBfcmVzLAogICAgYEhvbWljaWRlcyBwZXIgMSwwMDAgUmVzaWRlbnRzYCA9IGhvbWljaWRlX3Nob290aW5nc19wZXJfMTAwMF9yZXMsCiAgICBgUm9iYmVyeSBwZXIgMSwwMDAgUmVzaWRlbnRzYCA9IHJvYmJlcnlfcGVyXzEwMDBfcmVzLAogICAgYEFnZy4gQXNzYXVsdCBwZXIgMSwwMDAgUmVzaWRlbnRzYCA9IGFnZ19hc3NhdWx0X3Blcl8xMDAwX3JlcywKICAgIGBSYXBlIHBlciAxLDAwMCBSZXNpZGVudHNgID0gcmFwZV9wZXJfMTAwMF9yZXMpICU+JQogIHBpdm90X2xvbmdlcigtTmVpZ2hib3Job29kKSAlPiUKICBnZ3Bsb3QoYWVzKE5laWdoYm9yaG9vZCwgdmFsdWUpKSArCiAgZmFjZXRfd3JhcChmYWNldHMgPSB+bmFtZSwgbmNvbCA9IDIsIHNjYWxlcyA9ICJmcmVlIikgKyAKICBnZW9tX2NvbCgpICsKICBjb29yZF9mbGlwKCkgKwogIHRoZW1lX2l0ZWFtX2dvb2dsZV9kb2NzKCkgICsKICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpKQpgYGAKCgpgYGB7ciBmaWcud2lkdGggPSA3LCBmaWcuaGVpZ2h0ID0gN30KaG9vZHNAZGF0YSAlPiUKICBmaWx0ZXIobGFiZWwgJWluJSBjKCJNaWx0b24tTW9udGZvcmQiLAogICAgICAgICAgICAgICAgICAgICAgIkNhcnJvbGx0b24gUmlkZ2UiLAogICAgICAgICAgICAgICAgICAgICAgIlBlbm4gTm9ydGgiLAogICAgICAgICAgICAgICAgICAgICAgIkJyb2Fkd2F5IEVhc3QiKSkgJT4lCiAgdHJhbnNtdXRlKAogICAgTmVpZ2hib3Job29kID0gbGFiZWwsCiAgICBgSWxsZWdhbCBEdW1waW5nIFNSc2AgPSBpbGxlZ2FsX2R1bXBpbmcsCiAgICBgUHJvcC4gIE1haW50ZW5hbmNlIFNSc2AgPSBwcm9wZXJ0eV9tYWludGVuYW5jZSwKICAgIGBSaWdodCBvZiBXYXkgU1JzYCA9IHJpZ2h0X29mX3dheSwKICAgIGBIb21pY2lkZXNgID0gaG9taWNpZGVfc2hvb3RpbmdzLAogICAgYFJvYmJlcnlgID0gcm9iYmVyeSwKICAgIGBBZ2cuIEFzc2F1bHQgYCA9IGFnZ19hc3NhdWx0LAogICAgYFJhcGVgID0gcmFwZSkgJT4lCiAgcGl2b3RfbG9uZ2VyKC1OZWlnaGJvcmhvb2QpICU+JQogIGdncGxvdChhZXMoTmVpZ2hib3Job29kLCB2YWx1ZSkpICsKICBmYWNldF93cmFwKGZhY2V0cyA9IH5uYW1lLCBuY29sID0gMiwgc2NhbGVzID0gImZyZWUiKSArIAogIGdlb21fY29sKCkgKwogIGNvb3JkX2ZsaXAoKSArCiAgdGhlbWVfaXRlYW1fZ29vZ2xlX2RvY3MoKSAgKwogIHRoZW1lKGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCkpCmBgYA==